package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.dto.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.minio.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ApArticle;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.WmChannel;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmSensitive;
import com.heima.media.entity.WmUser;
import com.heima.media.feign.ArticleFeign;
import com.heima.media.service.*;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * @Author WSJ
 * @Date 2022-03-14-15:34
 * @Version 1.0 （版本号）
 */
@Service
public class AuditServiceImpl implements IAuditService {
    @Autowired
    private GreenTextScan textScan;

    @Autowired
    private GreenImageScan imageScan;

    @Autowired
    private IWmNewsService wmNewsService;

    @Autowired
    private ArticleFeign articleFeign;

    @Autowired
    private IWmSensitiveService wmSensitiveService;

    @Autowired
    private MinIOService minIOService;
    @Autowired
    private IWmUserService wmUserService;
    @Autowired
    private IWmChannelService wmChannelService;

    @Override
    @Async
    public void audit(WmNews wmNews) {
        if (wmNews.getStatus()==8||wmNews.getStatus()==4) {
            if (wmNews.getPublishTime().getTime()<=System.currentTimeMillis()) {
                //直接发布文章
                saveArticle(wmNews);
                return;
            }else {
                publishBehind(wmNews);
            }
        }
        //获取自媒体文章内容中的text和image
        String content = wmNews.getContent();
        List<ContentDto> dtos = JSON.parseArray(content, ContentDto.class);
        List<String> imageList=new ArrayList<>();
        StringBuilder text=new StringBuilder();
        if (dtos.size()>0) {
            for (ContentDto contentDto : dtos) {
                if ("text".equals(contentDto.getType())) {
                    text.append(contentDto.getValue());
                }else {
                    imageList.add(contentDto.getValue());
                }
            }
        }
        //审核自定义敏感词
        Boolean audit=auditFromSql(wmNews,text.toString());
        if (!audit) {
            return;
        }
        //阿里云审核文本
        Boolean aBoolean = auditTextByAliyun(wmNews, text.toString());
        if (!aBoolean) {
            return;
        }
        //阿里云审核图片
        Boolean imageBoolean=auditImageByAliyun(wmNews,imageList);
        if (!imageBoolean) {
            return;
        }
        //全部通过，判断发布时间是否立即保存文章
        if (wmNews.getPublishTime().getTime()<System.currentTimeMillis()) {
            saveArticle(wmNews);
        }else {
            //延迟执行
            publishBehind(wmNews);
        }
    }

    /**
     * 延时发布文章
     * @param wmNews
     */
    private void publishBehind(WmNews wmNews) {
        wmNews.setStatus(8);
        wmNewsService.updateById(wmNews);
        RBlockingDeque<Object> deque = client.getBlockingDeque("article_publish");
        RDelayedQueue<Object> queue = client.getDelayedQueue(deque);
        queue.offerAsync(JSON.toJSONString(wmNews),wmNews.getPublishTime().getTime()-System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }
    @Autowired
    private RedissonClient client;
    /**
     * 保存文章
     * @param wmNews
     * @return
     */
    private void saveArticle(WmNews wmNews) {
        ArticleDto apArticle=new ArticleDto();
        BeanUtils.copyProperties(wmNews,apArticle);
        apArticle.setId(null);
        LambdaQueryWrapper<WmUser> query = new LambdaQueryWrapper<>();
        query.eq(WmUser::getId,wmNews.getUserId());
        WmUser wmUser = wmUserService.getOne(query);
        apArticle.setAuthorId(wmUser.getApAuthorId());
        apArticle.setAuthorName(wmUser.getName());
        WmChannel wmChannel = wmChannelService.getById(wmNews.getChannelId());
        apArticle.setChannelName(wmChannel.getName());
        apArticle.setLayout(wmNews.getType());
        apArticle.setFlag(0);
        //获取封面
        List<ImageDto> dtos = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        List<String> urlList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dtos)) {
            for (ImageDto imageDto : dtos) {
                urlList.add(imageDto.getUrl());
            }
        }
        if (urlList.size()>0) {
            String join = String.join(",", urlList);
            apArticle.setImages(join);
        }
        ResponseResult<Long> result = articleFeign.saveArticle(apArticle);
        //如果保存文章成功，设置状态和文章id
        if (result.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
            Long articleId = result.getData();
            wmNews.setStatus(9);
            wmNews.setArticleId(articleId);
            wmNewsService.updateById(wmNews);
        }
    }

    /**
     * 阿里云审核图片
     * @param wmNews
     * @param imageList
     * @return
     */
    private Boolean auditImageByAliyun(WmNews wmNews, List<String> imageList) {
        //获取封面图片列表
        List<ImageDto> dtos = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        //判断图片是否存在于imageList中，不存在则加入
        if (CollectionUtils.isNotEmpty(dtos)) {
            for (ImageDto imageDto : dtos) {
                if (!imageList.contains(imageDto.getUrl())) {
                    imageList.add(imageDto.getUrl());
                }
            }
        }
        //判断是否存在图片
        if (imageList.size()==0) {
            //没图片，直接返回true
            return true;
        }
        //部署在外网，可以直接使用url审核
        //部署在本地，需要下载
        List<byte[]> imagesByte = new ArrayList<>();
        for (String url : imageList) {
            InputStream inputStream = minIOService.download(url);
            try {
                imagesByte.add(IOUtils.toByteArray(inputStream));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //审核
        try {
            Map map = imageScan.imageScan(imagesByte);
            String suggestion = (String) map.get("suggestion");
            //根据审核结果设置状态
            switch (suggestion){
                case "pass":{
                    //审核通过
                    return true;
                }
                case "block":{
                    //审核失败，设置失败原因和状态
                    wmNews.setStatus(2);
                    wmNews.setReason("阿里云图片审核失败："+map.get("label"));
                    wmNewsService.updateById(wmNews);
                    break;
                }
                case "review":{
                    //需要进一步人工审核
                    wmNews.setStatus(3);
                    wmNewsService.updateById(wmNews);
                    break;
                }
                default:
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 阿里云审核文本
     * @param wmNews
     * @param text
     * @return
     */
    public Boolean auditTextByAliyun(WmNews wmNews, String text) {
        try {
            //阿里云审核文本
            Map map = textScan.greenTextScan(wmNews.getTitle() + wmNews.getLabels() + text);
            String suggestion = (String) map.get("suggestion");
            //根据审核结果设置状态
            switch (suggestion){
                case "pass":{
                    //审核通过
                    return true;
                }
                case "block":{
                    //审核失败，设置失败原因和状态
                    wmNews.setStatus(2);
                    wmNews.setReason("阿里云文本审核失败："+map.get("label"));
                    wmNewsService.updateById(wmNews);
                    break;
                }
                case "review":{
                    //需要进一步人工审核
                    wmNews.setStatus(3);
                    wmNewsService.updateById(wmNews);
                    break;
                }
                default:
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 审核自定义敏感词
     * @param wmNews
     * @param text
     * @return
     */
    private Boolean auditFromSql(WmNews wmNews, String text) {
        //获取敏感词集合
        //构建查询条件
        LambdaQueryWrapper<WmSensitive> query=new LambdaQueryWrapper<>();
        query.select(WmSensitive::getSensitives);
        //查询
        List<String> list = wmSensitiveService.listObjs(query, o -> o.toString());
        //生成关键字字典库
        if (SensitiveWordUtil.dictionaryMap.size()==0) {
            SensitiveWordUtil.initMap(list);
        }
        //优先审核标题和标签
        Map<String, Integer> map = SensitiveWordUtil.matchWords(wmNews.getTitle() + wmNews.getLabels());
        if (map.size()!=0) {
            //审核不通过，获取原因
            StringBuilder reason=new StringBuilder();
            for (String s : map.keySet()) {
                reason.append(s);
            }
            // 修改不通过原因，修改状态
            wmNews.setStatus(2);
            wmNews.setReason("审核失败："+reason);
            wmNewsService.updateById(wmNews);
            return false;
        }
        //通过后审核文本内容
        Map<String, Integer> textMap = SensitiveWordUtil.matchWords(text);
        if (textMap.size()!=0) {
            //审核不通过，获取原因
            StringBuilder reason=new StringBuilder();
            for (String s : textMap.keySet()) {
                reason.append(s);
            }
            // 修改不通过原因，修改状态
            wmNews.setStatus(2);
            wmNews.setReason("审核失败："+reason);
            wmNewsService.updateById(wmNews);
            return false;
        }
        //都通过了，返回true
        return true;
    }
}
